package com.caits.lbs.framework.controller;


import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.HashMap;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.logging.log4j.Logger;
import org.springframework.util.Assert;

import com.caits.lbs.framework.Constants;
import com.caits.lbs.framework.bean.common.ApiParam;
import com.caits.lbs.framework.bean.common.ApiResult;
import com.caits.lbs.framework.bean.common.ApiResultHead;
import com.caits.lbs.framework.interceptor.ApiParamInterceptor;
import com.caits.lbs.framework.services.sms.IMessageService;
import com.caits.lbs.framework.services.sms.MessageSMS;
import com.caits.lbs.framework.utils.ApiResultBase64Util;
import com.caits.lbs.framework.utils.FileUtils;
import com.caits.lbs.framework.utils.StringUtils;


/**
 * <p>BaseController</p>
 * <p>mvc控制类的基础类</p>
 *
 * @author		周华彬(zhouhuabin@chinatransinfo.com, zhou_hua_bin@163.com)
 * @version		0.0.0
 * <table style="border:1px solid gray;">
 * <tr>
 * <th width="100px">版本号</th><th width="100px">动作</th><th width="100px">修改人</th><th width="100px">修改时间</th>
 * </tr>
 * <!-- 以 Table 方式书写修改历史 -->
 * <tr>
 * <td>0.0.0</td><td>创建类</td><td>zhouhuabin</td><td>2015年10月22日 上午10:11:35</td>
 * </tr>
 * <tr>
 * <td>XXX</td><td>XXX</td><td>XXX</td><td>XXX</td>
 * </tr>
 * </table>
*/
public abstract class BaseController {

	
	protected final Logger LOG = Constants.LOG4J;
	protected static final Logger SLOG = Constants.LOG4J;
	/** 内容类型(json,utf8)*/
	public final static String CHARSET_UTF8 = FileUtils.CONST_UTF8_CHARSET;
	
	/** 内容类型(json,utf8)*/
	public final static String ContentTypeJsonUtf8 = "application/json;charset=UTF-8";
	/** 内容类型(text,utf8)*/
	public final static String ContentTypeTextUtf8 = "text/plain;charset=UTF-8";
	/** 内容类型(xml,utf8)*/
	public final static String ContentTypeXmlUtf8 = "application/xml;charset=UTF-8";
	/** 内容类型(二进制流格式)*/
	public final static String ContentTypeBin = "application/octet-stream";
	/** 内容类型Content-Disposition,下载文件名称*/
	public final static String ContentTypeDisposition = "attachment;filename=";
	/** 变量:附件key,类型:String */
	public final static String ContentDisposition="Content-Disposition";
	/** 内容类型(压缩文件格式)*/
	public final static String ContentTypeZip = "application/zip";
	
	/** 短信服务接口 */
	private IMessageService messageService;
	/** 变量:返回结果的消息key,类型:String */
	public static final String RESULTMSG = "return_msg";
	/** 变量:返回的数据对象key,类型:String */
	public static final String RESULTDATA = "data";
	/** 变量:返回结果的状态码key,类型:String */
	public static final String RESULTCODE = "return_code";
	/** 返回码:成功 */
	public static final String RESULTCODE_SUCCESS = "200";
	/** 返回码:服务器错误 */
	public static final String RESULTCODE_SERVERERROR = "500";
	/** 返回码:结果为空 */
	public static final String RESULTCODE_RESULTISNULL = "910";
	/**
	 * 向http响应输出数据 
	 * @param request
	 * @param response
	 * @param returnValue
	 * @param format
	 * @param serviceName
	 */
	protected void fileFormation(String returnCode, HttpServletResponse response, String returnValue,
			String format, String serviceName) {
		String checkFile = checkResultValue(returnValue);
		if (!checkFile.equals(Constants.RESULTCODE_SUCCESS)) {
			response.addHeader(Constants.RESULTCODE, checkFile);
			LOG .info("{}接口调用,返回结果为空! resultCode:{}", serviceName, checkFile);
			return;
		}
		format = getReturnType(format);
		OutputStream os = null;
		try {
			response.setCharacterEncoding(CHARSET_UTF8);
			response.addHeader(Constants.RESULTCODE, returnCode);
			byte[] returnData = returnValue.getBytes(CHARSET_UTF8);
			int length = returnData.length;
			if (Constants.RESULT_TYPE_XML.equals(format)) {
				response.setContentType(ContentTypeXmlUtf8);
			} else if (Constants.RESULT_TYPE_JSON.equals(format)) {
				response.setContentType(ContentTypeJsonUtf8);
			}
			// --------------如果下个版本增加别的格式数据在从这扩展----------------
			os = response.getOutputStream();
			if (os != null) {
				os.write(returnData);
			}
			LOG.info("{}接口调用成功,返回数据length={}bytes!", serviceName,length);
		} catch (IOException e) {
			LOG.error("返回客户端数据异常,msg="+e.getLocalizedMessage(), e);
			response.setHeader(Constants.RESULTCODE, Constants.RESULTCODE_SERVERERROR);
			LOG.error("{} resultCode:{}", serviceName, Constants.RESULTCODE_SERVERERROR);
		} finally {
			try {
				if (os != null) {
					os.close();
				}
			} catch (IOException e) {
				LOG.error("关闭连接出错,msg="+e.getLocalizedMessage());
			}
		}

	}
	/**
	 * 以文本方式输出 
	 * @param returnCode
	 * @param response
	 * @param returnValue
	 * @param format
	 * @param serviceName void
	 */
	protected void fileFormationText(String returnCode, HttpServletResponse response, String returnValue,
			String format, String serviceName) {
		String checkFile = checkResultValue(returnValue);
		if (!checkFile.equals(Constants.RESULTCODE_SUCCESS)) {
			response.addHeader(Constants.RESULTCODE, checkFile);
			LOG .info("{}接口调用,返回结果为空! resultCode:{}", serviceName, checkFile);
			return;
		}
		format = getReturnType(format);
		OutputStream os = null;
		try {
			response.setCharacterEncoding(CHARSET_UTF8);
			response.addHeader(Constants.RESULTCODE, returnCode);
			byte[] returnData = returnValue.getBytes(CHARSET_UTF8);
			int length = returnData.length;
			response.setContentType(ContentTypeTextUtf8);
			// --------------如果下个版本增加别的格式数据在从这扩展----------------
			os = response.getOutputStream();
			if (os != null) {
				os.write(returnData);
			}
			LOG.info("{}接口调用成功,返回数据length={}bytes!", serviceName,length);
		} catch (IOException e) {
			LOG.error("返回客户端数据异常,msg="+e.getLocalizedMessage(), e);
			response.setHeader(Constants.RESULTCODE, Constants.RESULTCODE_SERVERERROR);
			LOG.error("{} resultCode:{}", serviceName, Constants.RESULTCODE_SERVERERROR);
		} finally {
			try {
				if (os != null) {
					os.close();
				}
			} catch (IOException e) {
				LOG.error("关闭连接出错,msg="+e.getLocalizedMessage());
			}
		}

	}
	/**
	 * 返回客户端文件 
	 * @param response
	 * @param bitData
	 * @param name
	 * @param serviceName
	 */
	protected void fileDownload(HttpServletResponse response, byte[] bitData, String name, String serviceName) {
		OutputStream os = null;
		ByteArrayInputStream bais = null;
		try {
			response.setCharacterEncoding(CHARSET_UTF8);
			response.addHeader(Constants.RESULTCODE, Constants.RESULTCODE_SUCCESS);
			int length = bitData.length;
			response.setContentType(ContentTypeBin);
			response.setContentLength(length);
			response.addHeader(ContentDisposition,ContentTypeDisposition+name);
			// --------------如果下个版本增加别的格式数据在从这扩展----------------
			os = response.getOutputStream();
			if (os != null) {
				os.write(bitData);
			}
			LOG.info("{}接口调用成功,返回数据length={}bytes!", serviceName,length);
		} catch (IOException e) {
			LOG.error("返回客户端数据异常,msg="+e.getLocalizedMessage(), e);
			response.setHeader(Constants.RESULTCODE, Constants.RESULTCODE_SERVERERROR);
			LOG.error("{} resultCode:{}", serviceName, Constants.RESULTCODE_SERVERERROR);
		} finally {
			try {
				if (bais != null) {
					bais.close();
				}
				if (os != null) {
					os.close();
				}
			} catch (IOException e) {
				LOG.error("关闭连接出错,msg="+e.getLocalizedMessage());
			}
		}

	}

	/**
	 * 检查返回数据格式
	 * 
	 * @param format
	 * @return
	 */
	protected String checkFormat(String format) {
		if (StringUtils.notNullOrBlank(format)) {
			if (!format.equals("xml") && !format.equals("json"))
				return Constants.PARAMCHECK_ERR;
		}
		return Constants.PARAMCHECK_OK;
	}

	/**
	 * 检查返回结果
	 * @param returnValue
	 * @return
	 */
	protected String checkResultValue(String returnValue) {
		if (StringUtils.isNullOrBlank(returnValue)) {
			return Constants.RESULTCODE_RESULTISNULL;
		}
		return Constants.RESULTCODE_SUCCESS;
	}


	/**
	 * 获取默认返回格式
	 * 
	 * @param returnType
	 * @return String
	 */
	protected String getReturnType(String returnType) {
		return StringUtils.null2default(returnType, Constants.RESULT_TYPE_JSON);
	}
	/**
	 * 构建通用返回<tt>map</tt>对象
	 * @param resultCode	响应代码
	 * @param	msg			响应的提示消息,<tt>null</tt>时则用<strong>成功</strong>代替
	 * @param	data		返回的数据对象
	 * @return Map<String,Object>
	 */
	protected Map<String,Object> buildCommonReturnMap(String resultCode,String msg,Object data){
		Map<String,Object> map = new HashMap<String,Object>();
		map.put(Constants.RESULTCODE,resultCode);
		map.put(Constants.RESULTMSG,StringUtils.null2default(msg,"成功"));
		if(data!=null){
			map.put(Constants.RESULTDATA,data);
		}
		return map;
	}
	/**
	 * 发送短信 
	 * @param mobile	接收手机号，多个号码以逗号分隔
	 * @param text		短信内容
	 * @param data		返回时额外的数据
	 * @return Map<String,Object>
	 */
	protected Map<String,Object> sendMessageReturnMap(String mobile,String text,Object data){
		Map<String,Object> map = new HashMap<String,Object>();
		try{
			Assert.notNull(messageService, "短信发送服务对象不能为空");
			/** 短信消息体 */
			MessageSMS message = new MessageSMS();
			message.setHead(mobile);
			message.setBody(text);
			messageService.sendMessage(message);
			map.put(Constants.RESULTCODE,Constants.RESULTCODE_SUCCESS);
			map.put(Constants.RESULTMSG,StringUtils.null2default(mobile,"发送短信成功"));
		}catch(Exception e){
			LOG.info("发送短信异常msg={}!", e.getLocalizedMessage());
			map.put(Constants.RESULTCODE,Constants.RESULTCODE_SERVERERROR);
			map.put(Constants.RESULTMSG,StringUtils.null2default(mobile,"发送短信失败"));
		}
		if(data!=null){
			map.put(Constants.RESULTDATA,data);
		}
		return map;
	}
	/**
	 * 向Response写入Json响应
	 * @param response
	 * @param apiResult
	 */
	public static void writeJsonResponse(HttpServletResponse response, ApiResult apiResult, String apiAuthKey) {
		try {
			response.setContentType(ContentTypeJsonUtf8);
			String returnValue = ApiResultBase64Util.encode(apiResult, apiAuthKey);
			response.getWriter().println(returnValue);
			response.getWriter().flush();
			byte[] returnData = returnValue.getBytes(CHARSET_UTF8);
			int length = returnData.length;
			if (length <= Constants.Common.LOGOUT_MAXLENGTH){
				SLOG.info("接口调用成功,返回数据:" + returnValue);
			}
			SLOG.info("接口调用成功,返回数据length=" + length + "bytes!");
		} catch (IOException e) {
			SLOG.error("返回客户端数据异常,msg=" + e.getLocalizedMessage(), e);
			response.setHeader(RESULTCODE, RESULTCODE_SERVERERROR);
			SLOG.error(" resultCode:" + RESULTCODE_SERVERERROR);
		}
	}

	/**
	 * 从请求中返回整个参数对象
	 * @param request
	 * @return
	 * @return 返回ApiParam<?>
	 */
	protected ApiParam<?> getApiParamFromRequest(HttpServletRequest request) {
		return (ApiParam<?>) request.getAttribute(Constants.Common.WEB_REQUEST_PARAM);
	}


	/**
	 * 返回异常信息
	 * @param response
	 * @param apiParamObj
	 * @param method
	 * @param ex
	 */
	public void writeException(HttpServletResponse response,ApiParam<?> apiParamObj,String method,Exception ex){
		LOG.error(method + "处理异常", ex);
		ApiResultHead head = ApiResultHead.getERROR(Constants.Common.ERROR);
		head.setSequenceCode(apiParamObj.getHead().getSequenceCode());
		head.setErrorMessage(ex.getMessage());
		ApiResult<Object> apiResult = new ApiResult<Object>(head);
		apiResult.setBody(ex.getMessage());
		writeJsonResponse(response, apiResult, ApiParamInterceptor.getApiAuthKeyByVersion(apiParamObj.getHead().getProtocolVersion()));
	}

	/**
	 * 对简单类型进行构造一个map对象 
	 * @param dataBean
	 * @return 
	 * @return 返回Map<String,Object>
	 */
	protected Map<String, Object> buildPrimitiveBodyData(Object dataBean) {
		Map<String,Object> dataMap = new HashMap<String,Object>();
		dataMap.put(RESULTDATA,dataBean);
		return dataMap;
	}
}
